import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Logger;


public class BasicFileProcessor implements FileProcessor{

	Logger LOG;
	public BasicFileProcessor(Logger log){
		LOG = log;
	}

	/* (non-Javadoc)
	 * @see FileProcessor#processAuxFile(java.io.File)
	 */
	@Override
	public int processAuxFile(File aux) throws IOException{
		int value = 0;
		int next = 0;
		BufferedInputStream auxStream = new BufferedInputStream(new FileInputStream(aux));


		next = auxStream.read();
		if(CharInfo.isASCIINonZeroDigit(next)){//If first byte corresponds to a non-zero digit, add it to value and get next byte
			value+=next-CharInfo.ASCIIZERO;
			next = auxStream.read();
		} else{//otherwise, log error and set next to -1, which will exit the program and return 0 (signifying invalid input)
			LOG.severe("006: Invalid auxillary input file. First character must be an ASCII digit other than 0");
			next = -1;
		}


		while(CharInfo.isASCIIDigit(next)){//Keep reading next byte until a non-ASCII digit is found
			value*=10;
			value+=next-CharInfo.ASCIIZERO;
		}


		boolean fail;
		if (next==-1){//we're at the end of file. this is good.
			fail=false;
		} else if (next == CharInfo.MACNEWLINE){//We could be good if the new line is followed by the end of file;
			next = auxStream.read();
			fail = (next != -1);
		} else{//bad input file
			fail = true;
		}
		if (fail){//set value to 0 (signifying invalid input), log error
			LOG.severe("007: Invalid auxillary input file. File must contain an ASCII number followed by either (only) a new line, or nothing");
			value = 0;
		}
			closeQuietly(auxStream);
		return value;
	}

	/* (non-Javadoc)
	 * @see FileProcessor#processPrimaryFile(java.io.File, java.io.File, int, int)
	 */
	@Override
	public void processPrimaryFile(File prim, File out, int numLines, int lineLength) throws IOException{
		BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(prim));
		BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(out));

		int overflowLines = 0;
		int totalLines = 0;
		int result = 0;


		while(result!=-1){//while we're not at the end of file
			totalLines++;
			if(totalLines<numLines){//if we're not at the line cap, print the line
				result = processAndPrintLine(inStream, outStream, lineLength);
				if(result % 2 == 0 ){//if we overflow, log it and increment counter
					overflowLines++;
					LOG.info("Line "+totalLines+" contains more than "+lineLength+" printable bytes.\n");
				}
				if (result != -1){//if we're not at the end of file, we're at a new line
					outStream.write(CharInfo.MACNEWLINE);
				}
			}else{//else we're past the limit, don't print the line
				result = processNoPrintLine(inStream);
			}
		}
		
		
		int actual;//find actual number of lines output
		if(totalLines<numLines){
			actual = totalLines;
		}else{
			actual = numLines;
		}
		LOG.info(actual+" lines were produced in file " + out.toString()+".");
		LOG.info("File " + prim + " contained "+ totalLines + " total.");
		LOG.info("There were "+overflowLines+" lines that overflowed total.");
		closeQuietly(inStream);
		closeQuietly(outStream);

	} 
	private int processAndPrintLine(InputStream in, OutputStream out, int lineLength) throws IOException{
		int result = 1;//return -1 for EOF, 2 for overflow, -2 for overflow and EOF, 1 otherwise
		int index = 0;
		int next = in.read();
		while(!(next==-1 || next == CharInfo.MACNEWLINE)){//keep going until end of file or new line is found
			if(CharInfo.isASCIIPrintable(next) && index < lineLength){//if it's writeable and we're not at the char limit, write it
				out.write(next);
			} else{//otherwise result = 2 for overflow
				result = 2;
			}
			next = in.read();
		}
		if(next == -1){//if we hit EOF, multiply by -1
			result *= -1;//this gives us -2 if we overflow, -1 otherwise
		}
		return result;
	}
	private int processNoPrintLine(InputStream in) throws IOException{
		int result = 1;//return -1 for end of file, 1 otherwise
		int next = in.read();
		while(!(next==-1 || next == CharInfo.MACNEWLINE)){//keep going until end of file or new line is found
			next = in.read();
		}
		if (next == -1){//if we hit EOF return -1, 1 otherwise
			result = -1;
		}
		return result;
	}
	private void closeQuietly(Closeable stream){
		if(stream!=null){
			try {
				stream.close();
			} catch (IOException e) {
				//ignore, we've got everything we need
			}
		}
	}

}

